﻿namespace ScrumLite.Services
{
    using System.Collections.Generic;
    using System.DirectoryServices.AccountManagement;
    using System.Security.Authentication;
    using System.Security.Permissions;
    using System.DirectoryServices;
    using ScrumLite.Services.Contracts;
    using System.Collections.ObjectModel;
    using System.Linq;
    using ScrumLite.Data;

    public class ActiveDirectoryProfileService : IProfileService
    {        
        public ActiveDirectoryProfileService()
        {
        }

        [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
        public string GetFullName(string samAccountName)
        {
            PrincipalContext context;

            try
            {
                context = new PrincipalContext(ContextType.Domain);
            }
            catch (PrincipalServerDownException)
            {
                context = new PrincipalContext(ContextType.Machine);
            }

            UserPrincipal user = UserPrincipal.FindByIdentity(
                context,
                IdentityType.SamAccountName,
                samAccountName);
            
            string displayName;
            if (user == null)
            {
                displayName = "Anonymous";
            }
            else
            {
                displayName = user.DisplayName;
            }

            context.Dispose();
            return displayName;
        }

        [SecurityPermission(SecurityAction.LinkDemand)]
        public string[] GetUserRoles(string samAccountName)
        {
            PrincipalContext context;
            List<string> groups = null;

            try
            {
                context = new PrincipalContext(ContextType.Domain);
            }
            catch (PrincipalServerDownException)
            {
                context = new PrincipalContext(ContextType.Machine);
            }

            UserPrincipal user = UserPrincipal.FindByIdentity(
                context,
                IdentityType.SamAccountName,
                samAccountName);

            if (user == null)
                throw new AuthenticationException("The user does not exists.");

            PrincipalSearchResult<Principal> groupPrincipals = user.GetGroups(context);

            if (groupPrincipals != null)
            {
                groups = new List<string>();
                foreach (GroupPrincipal group in groupPrincipals)
                {                    
                    groups.Add(group.Name);
                }
            }

            return groups.ToArray();
        }

        [SecurityPermission(SecurityAction.LinkDemand)]
        public bool IsUserInRole(string samAccountName, string role)
        {
            PrincipalContext context;
            
            try
            {
                context = new PrincipalContext(ContextType.Domain);
            }
            catch (PrincipalServerDownException)
            {
                context = new PrincipalContext(ContextType.Machine);
            }

            UserPrincipal user = UserPrincipal.FindByIdentity(
                context,
                IdentityType.SamAccountName,
                samAccountName);

            if (user == null)
                throw new AuthenticationException("The user does not exists");

            bool userIsInRole;
            try
            {
                userIsInRole = user.IsMemberOf(context, IdentityType.SamAccountName, role);            
            }
            catch (NoMatchingPrincipalException) {
                userIsInRole = false;
            }

            return userIsInRole;
        }

        [SecurityPermission(SecurityAction.LinkDemand)]
        public Collection<Person> GetPeople()
        {
            PrincipalContext context;

            try
            {
                context = new PrincipalContext(ContextType.Domain);
            }
            catch (PrincipalServerDownException)
            {
                context = new PrincipalContext(ContextType.Machine);
            }

            UserPrincipal principalUser = new UserPrincipal(context);
            PrincipalSearcher searcher = new PrincipalSearcher();
            searcher.QueryFilter = principalUser;
            PrincipalSearchResult<Principal> results = searcher.FindAll();
            List<Person> people = new List<Person>();

            foreach (UserPrincipal result in results)
            {
                string name = string.Empty;
                string EmailAddress = (!string.IsNullOrEmpty(result.EmailAddress) ? result.EmailAddress : string.Empty);
                string personId = (string)result.SamAccountName;
                if (!string.IsNullOrEmpty(result.DisplayName))
                {
                    name = (string)result.DisplayName;
                }
                else
                {
                    name = (string)result.SamAccountName;
                }

                Person person = new Person { Id = personId, Name = name, Mail = EmailAddress };

                people.Add(person);
            }

            searcher.Dispose();

            ExcludedUserStore store = new ExcludedUserStore();

            string[] excluded = store.GetExcludedUsers();

            people.RemoveAll(delegate(Person p)
            {
                if (excluded.Contains(p.Id))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            });

            return new Collection<Person>(people);
        }
    }
}
